<!doctype html>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="../assert_selection.js"></script>
<script>
// For https://bugs.webkit.org/show_bug.cgi?id=57340, which introduce
// VisibleSelection::Visible{Base,Extent}() and |original_base_| in
// |SelectionController|.

// TODO(editing-dev): We should make this test faster[1], e.g. do not drag
// all characters.
// [1] http://crbug.com/741259
const kFontSize = '20px';
const kMouseStep = 5;

function fold(string) {
  const results = [];
  for (let i = 0; i < string.length; i++) {
    let code = string.charCodeAt(i);
    if (0x05d0 <= code && code <= 0x05ea)// Hebrew Alef
        code += -0x05d0 + 'A'.charCodeAt(0);
    results.push(String.fromCharCode(code));
  }
  return results.join('');
}

function startDrag(x, y) {
  assert_own_property(window, 'eventSender', 'This test requires window.eventSender');
  eventSender.dragMode = false;

  // Clear click count
  eventSender.mouseMoveTo(0, 0);
  eventSender.mouseDown();
  eventSender.mouseUp();

  eventSender.mouseMoveTo(x, y);
  eventSender.mouseDown();
}

function endDrag() {
  eventSender.mouseUp();
}

class StaticRange {
  constructor(selection) {
    this.anchorNode_ = selection.anchorNode;
    this.anchorOffset_ = selection.anchorOffset;
    this.focusNode_ = selection.focusNode;
    this.focusOffset_ = selection.focusOffset;
  }

  equals(other) {
    return this.anchorNode_ == other.anchorNode_ &&
           this.anchorOffset_ == other.anchorOffset_ &&
           this.focusNode_ == other.focusNode_ &&
           this.focusOffset_ == other.focusOffset_;
  }
}

function moveRightUntilSelectionChanged(selection, left, right, y) {
  const startRange = new StaticRange(selection);
  for (let x = left; x <= right; x += kMouseStep) {
    eventSender.mouseMoveTo(x, y);
    if (!startRange.equals(new StaticRange(selection)))
      return x;
  }
  throw 'moveRightUntilSelectionChanged failed';
}

function moveLeftUntilSelectionChanged(selection, left, right, y) {
  const startRange = new StaticRange(selection);
  for (let x = right; x >= left; x -= kMouseStep) {
    eventSender.mouseMoveTo(x, y);
    if (!startRange.equals(new StaticRange(selection)))
      return x;
  }
  throw 'moveLeftUntilSelectionChanged failed';
}

function dragLeftToRight(selection, count) {
  const target = selection.document.querySelector('.target');
  const left = selection.computeLeft(target);
  const right = left + target.offsetWidth;
  const y = selection.computeTop(target);
  startDrag(left, y);
  let x = left;
  for (let i = 0; i < count; ++i)
    x = moveRightUntilSelectionChanged(selection, x, right, y);
  endDrag();
}

function dragRightToLeft(selection, numberOfSelectionChanges) {
  const target = selection.document.querySelector('.target');
  const left = selection.computeLeft(target);
  const right = left + target.offsetWidth - 1;
  const y = selection.computeTop(target);
  startDrag(right, y);
  let x = right;
  for (let i = 0; i < numberOfSelectionChanges; ++i)
    x = moveLeftUntilSelectionChanged(selection, left, x, y);
  endDrag();
}

function testIt(drag, caseIndex, count, sample, expected, expectedText) {
  test(() => assert_selection(
    sample,
    selection => {
      selection.document.body.style.fontFamily = 'monospace';
      selection.document.body.style.fontSize = kFontSize;
      drag(selection, count);
      assert_equals(fold(selection.toString()), expectedText);
    },
    expected),
    `${caseIndex}-${count}: ${drag.name} expects "${expectedText}".`);
}

const kSample1 = '<span class="target">abc\u05d0\u05d1\u05d2</span>';
testIt(dragLeftToRight, 1, 1, kSample1,
    '<span class="target">^a|bc\u05d0\u05d1\u05d2</span>', 'a');
testIt(dragLeftToRight, 1, 2, kSample1,
    '<span class="target">^ab|c\u05d0\u05d1\u05d2</span>', 'ab');
testIt(dragLeftToRight, 1, 3, kSample1,
    '<span class="target">^abc|\u05d0\u05d1\u05d2</span>', 'abc');
testIt(dragLeftToRight, 1, 4, kSample1,
    '<span class="target">^abc\u05d0\u05d1|\u05d2</span>', 'abcAB');
testIt(dragLeftToRight, 1, 5, kSample1,
    '<span class="target">^abc\u05d0|\u05d1\u05d2</span>', 'abcA');
testIt(dragLeftToRight, 1, 6, kSample1,
    '<span class="target">^abc\u05d0\u05d1\u05d2|</span>', 'abcABC');

testIt(dragRightToLeft, 1, 1, kSample1,
    '<span class="target">abc^\u05d0|\u05d1\u05d2</span>', 'A');
testIt(dragRightToLeft, 1, 2, kSample1,
    '<span class="target">abc^\u05d0\u05d1|\u05d2</span>', 'AB');
testIt(dragRightToLeft, 1, 3, kSample1,
    '<span class="target">abc|\u05d0\u05d1\u05d2^</span>', 'ABC');
testIt(dragRightToLeft, 1, 4, kSample1,
    '<span class="target">ab|c\u05d0\u05d1\u05d2^</span>', 'cABC');
testIt(dragRightToLeft, 1, 5, kSample1,
    '<span class="target">a|bc\u05d0\u05d1\u05d2^</span>', 'bcABC');
testIt(dragRightToLeft, 1, 6, kSample1,
    '<span class="target">|abc\u05d0\u05d1\u05d2^</span>', 'abcABC');

const kSample2 = '<span class="target">\u05d0\u05d1\u05d2def</span>';
testIt(dragLeftToRight, 2, 1, kSample2,
    '<span class="target">\u05d0\u05d1|\u05d2^def</span>', 'C');
testIt(dragLeftToRight, 2, 2, kSample2,
    '<span class="target">\u05d0|\u05d1\u05d2^def</span>', 'BC');
testIt(dragLeftToRight, 2, 3, kSample2,
    '<span class="target">^\u05d0\u05d1\u05d2|def</span>', 'ABC');
testIt(dragLeftToRight, 2, 4, kSample2,
    '<span class="target">^\u05d0\u05d1\u05d2d|ef</span>', 'ABCd');
testIt(dragLeftToRight, 2, 5, kSample2,
    // TODO(editing-dev): This should be 'ABCef' instead of 'ABCde'.
    '<span class="target">^\u05d0\u05d1\u05d2de|f</span>', 'ABCde');
testIt(dragLeftToRight, 2, 6, kSample2,
    '<span class="target">^\u05d0\u05d1\u05d2def|</span>', 'ABCdef');

testIt(dragRightToLeft, 2, 1, kSample2,
    '<span class="target">\u05d0\u05d1\u05d2de|f^</span>', 'f');
testIt(dragRightToLeft, 2, 2, kSample2,
    '<span class="target">\u05d0\u05d1\u05d2d|ef^</span>', 'ef');
testIt(dragRightToLeft, 2, 3, kSample2,
    '<span class="target">\u05d0\u05d1\u05d2|def^</span>', 'def');
testIt(dragRightToLeft, 2, 4, kSample2,
    '<span class="target">\u05d0|\u05d1\u05d2def^</span>', 'BCdef');
testIt(dragRightToLeft, 2, 5, kSample2,
    '<span class="target">\u05d0\u05d1|\u05d2def^</span>', 'Cdef');
testIt(dragRightToLeft, 2, 6, kSample2,
    '<span class="target">|\u05d0\u05d1\u05d2def^</span>', 'ABCdef');

const kSample3 = 'abc<span class="target">\u05d0\u05d1\u05d2</span>def';
testIt(dragLeftToRight, 3, 1, kSample3,
    'abc<span class="target">\u05d0\u05d1|\u05d2^</span>def', 'C');
testIt(dragLeftToRight, 3, 2, kSample3,
    'abc<span class="target">\u05d0|\u05d1\u05d2^</span>def', 'BC');
testIt(dragLeftToRight, 3, 3, kSample3,
    'abc<span class="target">^\u05d0\u05d1\u05d2|</span>def', 'ABC');

testIt(dragRightToLeft, 3, 1, kSample3,
    'abc<span class="target">^\u05d0|\u05d1\u05d2</span>def', 'A');
testIt(dragRightToLeft, 3, 2, kSample3,
    'abc<span class="target">^\u05d0\u05d1|\u05d2</span>def', 'AB');
testIt(dragRightToLeft, 3, 3, kSample3,
    'abc<span class="target">|\u05d0\u05d1\u05d2^</span>def', 'ABC');

const kSample4 = [
  '<div dir="rtl">',
    '<span class="target">\u05d0\u05d1\u05d2</span>def',
    '</div>',
].join('');
testIt(dragLeftToRight, 4, 1, kSample4,
    '<div dir="rtl"><span class="target">\u05d0\u05d1|\u05d2^</span>def</div>',
    'C');
testIt(dragLeftToRight, 4, 2, kSample4,
    '<div dir="rtl"><span class="target">\u05d0|\u05d1\u05d2^</span>def</div>',
    'BC');
testIt(dragLeftToRight, 4, 3, kSample4,
    '<div dir="rtl"><span class="target">|\u05d0\u05d1\u05d2^</span>def</div>',
    'ABC');

testIt(dragRightToLeft, 4, 1, kSample4,
    '<div dir="rtl"><span class="target">^\u05d0|\u05d1\u05d2</span>def</div>',
    'A');
testIt(dragRightToLeft, 4, 2, kSample4,
    '<div dir="rtl"><span class="target">^\u05d0\u05d1|\u05d2</span>def</div>',
    'AB');
testIt(dragRightToLeft, 4, 3, kSample4,
    '<div dir="rtl"><span class="target">^\u05d0\u05d1\u05d2|</span>def</div>',
    'ABC');

const kSample5 = '\u05d0\u05d1\u05d2d<span class="target">ef</span>';
testIt(dragLeftToRight, 5, 1, kSample5,
    '\u05d0\u05d1\u05d2d<span class="target">^e|f</span>', 'e');
testIt(dragLeftToRight, 5, 2, kSample5,
    '\u05d0\u05d1\u05d2d<span class="target">^ef|</span>', 'ef');

testIt(dragRightToLeft, 5, 1, kSample5,
    '\u05d0\u05d1\u05d2d<span class="target">e|f^</span>', 'f');
testIt(dragRightToLeft, 5, 2, kSample5,
    '\u05d0\u05d1\u05d2d<span class="target">|ef^</span>', 'ef');

const kSample6 = 'abc<span class="target">\u05d0\u05d1</span>\u05d2';
testIt(dragLeftToRight, 6, 1, kSample6,
    'abc<span class="target">\u05d0|\u05d1^</span>\u05d2', 'B');
testIt(dragLeftToRight, 6, 2, kSample6,
    'abc<span class="target">|\u05d0\u05d1^</span>\u05d2', 'AB');

testIt(dragRightToLeft, 6, 1, kSample6,
    'abc<span class="target">^\u05d0|\u05d1</span>\u05d2', 'A');
testIt(dragRightToLeft, 6, 2, kSample6,
    'abc<span class="target">^\u05d0\u05d1|</span>\u05d2', 'AB');

const kSample7 = 'a\u05e7\u05dc<span class="target">12</span>\u05d9\u05ddd';
testIt(dragLeftToRight, 7, 1, kSample7,
    'a\u05e7\u05dc<span class="target">^1|2</span>\u05d9\u05ddd', '1');
testIt(dragLeftToRight, 7, 2, kSample7,
    'a\u05e7\u05dc<span class="target">^12|</span>\u05d9\u05ddd', '12');

testIt(dragRightToLeft, 7, 1, kSample7,
    'a\u05e7\u05dc<span class="target">1|2^</span>\u05d9\u05ddd', '2');
testIt(dragRightToLeft, 7, 2, kSample7,
    'a\u05e7\u05dc<span class="target">|12^</span>\u05d9\u05ddd', '12');

const kSample8 = [
  '<div dir="rtl">',
    '<span class="target">\u05d0\u05d1\u05d2 123</span>',
  '</div>',
].join('');
testIt(dragLeftToRight, 8, 1, kSample8,
    '<div dir="rtl"><span class="target">\u05d0\u05d1\u05d2 ^1|23</span></div>',
    '1');
testIt(dragLeftToRight, 8, 2, kSample8,
    '<div dir="rtl"><span class="target">\u05d0\u05d1\u05d2 ^12|3</span></div>',
    '12');
testIt(dragLeftToRight, 8, 3, kSample8,
    '<div dir="rtl"><span class="target">\u05d0\u05d1\u05d2 |123^</span></div>',
    '123');
testIt(dragLeftToRight, 8, 4, kSample8,
    '<div dir="rtl"><span class="target">\u05d0\u05d1\u05d2| 123^</span></div>',
    ' 123');
testIt(dragLeftToRight, 8, 5, kSample8,
    '<div dir="rtl"><span class="target">\u05d0\u05d1|\u05d2 123^</span></div>',
    'C 123');
testIt(dragLeftToRight, 8, 6, kSample8,
    '<div dir="rtl"><span class="target">\u05d0|\u05d1\u05d2 123^</span></div>',
    'BC 123');
testIt(dragLeftToRight, 8, 7, kSample8,
    '<div dir="rtl"><span class="target">|\u05d0\u05d1\u05d2 123^</span></div>',
    'ABC 123');

testIt(dragRightToLeft, 8, 1, kSample8,
    '<div dir="rtl"><span class="target">^\u05d0|\u05d1\u05d2 123</span></div>',
    'A');
testIt(dragRightToLeft, 8, 2, kSample8,
    '<div dir="rtl"><span class="target">^\u05d0\u05d1|\u05d2 123</span></div>',
    'AB');
testIt(dragRightToLeft, 8, 3, kSample8,
    '<div dir="rtl"><span class="target">^\u05d0\u05d1\u05d2| 123</span></div>',
    'ABC');
testIt(dragRightToLeft, 8, 4, kSample8,
    '<div dir="rtl"><span class="target">^\u05d0\u05d1\u05d2 |123</span></div>',
    'ABC ');
testIt(dragRightToLeft, 8, 5, kSample8,
    '<div dir="rtl"><span class="target">^\u05d0\u05d1\u05d2 12|3</span></div>',
    'ABC 12');
testIt(dragRightToLeft, 8, 6, kSample8,
    '<div dir="rtl"><span class="target">^\u05d0\u05d1\u05d2 1|23</span></div>',
    'ABC 1');
testIt(dragRightToLeft, 8, 7, kSample8,
    '<div dir="rtl"><span class="target">^\u05d0\u05d1\u05d2 123|</span></div>',
    'ABC 123');

const kSample9 = '<span class="target">\u05d0\u05d1\u05d2 123</span>';
testIt(dragLeftToRight, 9, 1, kSample9,
    '<span class="target">\u05d0\u05d1\u05d2 ^1|23</span>', '1');
testIt(dragLeftToRight, 9, 2, kSample9,
    '<span class="target">\u05d0\u05d1\u05d2 ^12|3</span>', '12');
testIt(dragLeftToRight, 9, 3, kSample9,
    // TODO(editing-dev): This should be ' 123' instead of '123'.
    '<span class="target">\u05d0\u05d1\u05d2 ^123|</span>', '123');
testIt(dragLeftToRight, 9, 4, kSample9,
    // TODO(editing-dev): This should be 'C 123' instead of ' '.
    '<span class="target">\u05d0\u05d1\u05d2| ^123</span>', ' ');
testIt(dragLeftToRight, 9, 5, kSample9,
    // TODO(editing-dev): This should be 'BC 123' instead of 'C '.
    '<span class="target">\u05d0\u05d1|\u05d2 ^123</span>', 'C ');
testIt(dragLeftToRight, 9, 6, kSample9,
    // TODO(editing-dev): This should be 'ABC 123' instead of 'BC '.
    '<span class="target">\u05d0|\u05d1\u05d2 ^123</span>', 'BC ');
testIt(dragLeftToRight, 9, 7, kSample9,
    // TODO(editing-dev): This should be '' instead of '123'.
    '<span class="target">\u05d0\u05d1\u05d2 ^123|</span>', '123');

testIt(dragRightToLeft, 9, 1, kSample9,
    '<span class="target">^\u05d0|\u05d1\u05d2 123</span>', 'A');
testIt(dragRightToLeft, 9, 2, kSample9,
    '<span class="target">^\u05d0\u05d1|\u05d2 123</span>', 'AB');
testIt(dragRightToLeft, 9, 3, kSample9,
    '<span class="target">^\u05d0\u05d1\u05d2| 123</span>', 'ABC');
testIt(dragRightToLeft, 9, 4, kSample9,
    // TODO(editing-dev): This should be 'ABC ' instead of ''.
    '<span class="target">\u05d0\u05d1\u05d2 123|</span>', '');
testIt(dragRightToLeft, 9, 5, kSample9,
    '<span class="target">^\u05d0\u05d1\u05d2 12|3</span>', 'ABC 12');
testIt(dragRightToLeft, 9, 6, kSample9,
    '<span class="target">^\u05d0\u05d1\u05d2 1|23</span>', 'ABC 1');
testIt(dragRightToLeft, 9, 7, kSample9,
    // TODO(editing-dev): This should be 'ABC 123' instead of ''.
    '<span class="target">\u05d0\u05d1\u05d2 |123^</span>', '123');

// For https://bugs.webkit.org/show_bug.cgi?id=73056
const kStyle10 = 'position: absolute; left: 0px; top: 0px; z-index: -5;';
const kSample10 = [
  '<div style="position: relative;">',
    'a\u05d0\u05d1\u05d2b',
    `<div style="${kStyle10}">`,
      'a<span class="target">\u05d0\u05d1\u05d2</span>b',
     '</div>',
  '</div>'
].join('');

testIt(dragLeftToRight, 10, 1, kSample10,
    [
      '<div style="position: relative;">',
        'a\u05d0\u05d1|\u05d2^b',
        `<div style="${kStyle10}">`,
          'a<span class="target">\u05d0\u05d1\u05d2</span>b',
        '</div>',
      '</div>'
    ].join(''), 'C');
testIt(dragLeftToRight, 10, 2, kSample10,
    [
      '<div style="position: relative;">',
        'a\u05d0|\u05d1\u05d2^b',
        `<div style="${kStyle10}">`,
          'a<span class="target">\u05d0\u05d1\u05d2</span>b',
        '</div>',
      '</div>'
    ].join(''), 'BC');
testIt(dragLeftToRight, 10, 3, kSample10,
    [
      '<div style="position: relative;">',
        'a^\u05d0\u05d1\u05d2|b',
        `<div style="${kStyle10}">`,
          'a<span class="target">\u05d0\u05d1\u05d2</span>b',
        '</div>',
      '</div>'
    ].join(''), 'ABC');

testIt(dragRightToLeft, 10, 1, kSample10,
    [
      '<div style="position: relative;">',
        'a^\u05d0|\u05d1\u05d2b',
        `<div style="${kStyle10}">`,
          'a<span class="target">\u05d0\u05d1\u05d2</span>b',
        '</div>',
      '</div>'
    ].join(''), 'A');
testIt(dragRightToLeft, 10, 2, kSample10,
    [
      '<div style="position: relative;">',
        'a^\u05d0\u05d1|\u05d2b',
        `<div style="${kStyle10}">`,
          'a<span class="target">\u05d0\u05d1\u05d2</span>b',
        '</div>',
      '</div>'
    ].join(''), 'AB');
;
testIt(dragRightToLeft, 10, 3, kSample10,
    [
      '<div style="position: relative;">',
        'a|\u05d0\u05d1\u05d2^b',
        `<div style="${kStyle10}">`,
          'a<span class="target">\u05d0\u05d1\u05d2</span>b',
        '</div>',
      '</div>'
    ].join(''), 'ABC');

const kSample11 = '<span class="target" dir="rtl">\u05d0\u05d1\u05d2<br></span>';
testIt(dragLeftToRight, 11, 1, kSample11,
    '<span class="target" dir="rtl">\u05d0\u05d1|\u05d2^<br></span>', 'C');
testIt(dragLeftToRight, 11, 2, kSample11,
    '<span class="target" dir="rtl">\u05d0|\u05d1\u05d2^<br></span>', 'BC');
testIt(dragLeftToRight, 11, 3, kSample11,
    '<span class="target" dir="rtl">^\u05d0\u05d1\u05d2|<br></span>', 'ABC');

testIt(dragRightToLeft, 11, 1, kSample11,
    '<span class="target" dir="rtl">^\u05d0|\u05d1\u05d2<br></span>', 'A');
testIt(dragRightToLeft, 11, 2, kSample11,
    '<span class="target" dir="rtl">^\u05d0\u05d1|\u05d2<br></span>', 'AB');
testIt(dragRightToLeft, 11, 3, kSample11,
    '<span class="target" dir="rtl">|\u05d0\u05d1\u05d2^<br></span>', 'ABC');
</script>
